home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1994 March
/
Internet Info CD-ROM (Walnut Creek) (March 1994).iso
/
networking
/
ip
/
ka9q
/
crh_n.arc
/
NANSI_P.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-02-07
|
10KB
|
307 lines
;----- nansi_p.asm --------------------------------------------------------
; A state machine implementation of the mechanics of ANSI terminal control
; string parsing.
; (C) 1986 Daniel Kegel, Pasadena, CA
; May be distributed for educational and personal use only
;
; Entered with a jump to f_escape when driver finds an escape, or
; to f_in_escape when the last string written to this device ended in the
; middle of an escape sequence.
;
; Exits by jumping to f_ANSI_exit when an escape sequence ends, or
; to f_not_ANSI when a bad escape sequence is found, or (after saving state)
; to f_loopdone when the write ends in the middle of an escape sequence.
;
; Parameters are stored as bytes in param_buffer. If a parameter is
; omitted, it is stored as zero. Each character in a keyboard reassignment
; command counts as one parameter.
;
; When a complete escape sequence has been parsed, the address of the
; ANSI routine to call is found in ansi_fn_table.
;
; Register usage during parsing:
; DS:SI points to the incoming string.
; CX holds the length remaining in the incoming string.
; ES:DI points to the current location on the memory-mapped screen.
; DX is number of characters remaining on the current screen line.
; BX points to the current paramter byte being assembled from the incoming
; string. (Stored in cur_parm_ptr between device driver calls, if needed.)
;
; The registers are set as follows before calling the ANSI subroutine:
; AX = max(1, value of first parameter)
; CX = number of paramters
; SI = offset of second parameter from CS
; DS = CS
; ES:DI points to the current location on the memory-mapped screen.
; DX is number of characters remaining on the current screen line.
; The subroutine is free to trash AX, BX, CX, SI, and DS.
; It must preserve ES, and can alter DX and DI if it wants to move the
; cursor.
;
; Revision history:
; 7 July 85: created by DRK
;------------------------------------------------------------------------
; From nansi.asm
extrn f_not_ANSI:near ; exit: abort bad ANSI cmd
extrn f_ANSI_exit:near ; exit: good cmd done
extrn f_loopdone:near ; exit: ran out of chars. State saved.
extrn escvector:word ; saved state: where to jump
extrn cur_parm_ptr:word ; saved state: where to put next param
extrn string_term:byte ; saved state: what ends string
extrn cur_x:byte, max_x:byte ; 0 <= cur_x <= max_x
extrn cur_attrib:byte ; current color/attribute
extrn xlate_tab_ptr:word
; from nansi_f.asm
extrn ansi_fn_table:word ; ANSI subroutine table
; Used in nansi.asm
public f_escape ; entry: found an escape
public f_in_escape ; entry: restore state, keep parsing
; Used in nansi_i.asm and nansi_f.asm
public param_buffer, param_end, redef_end
code segment byte public 'CODE'
assume cs:code
; More saved state
in_num db ? ; true if between a digit and a semi in parse
param_buffer dw 3000h ; address of first byte free for new params
param_end dw 3060h ; address of end of free area
redef_end dw 3060h ; address of end of redefinition area
; These initialized values are only for debugging
;----- next_is -------------------------------------------------------
; Next_is is used to advance to the next state. If there are characters
; left in the input string, we jump immediately to the new state;
; otherwise, we shut down the recognizer, and wait for the next call
; to the device driver.
next_is macro statename
loop statename
mov ax, offset statename
jmp sleep
endm
;----- sleep --------------------------------------------------------
; Remember bx and next state, then jump to device driver exit routine.
; Device driver will re-enter at f_in_escape upon next invocation
; because escvector is nonzero; parsing will then be resumed.
sleep: mov cs:cur_parm_ptr, bx
mov cs:escvector, ax
jmp f_loopdone
;----- f_in_escape ---------------------------------------------------
; Main loop noticed that escvector was not zero.
; Recall value of BX saved when sleep was jumped to, and jump into parser.
f_in_escape:
mov bx, cs:cur_parm_ptr
jmp word ptr cs:escvector
fbr_syntax_error_gate: ; jumped to from inside f_bracket
jmp syntax_error
;----- f_escape ------------------------------------------------------
; We found an escape. Next character should be a left bracket.
f_escape:
next_is f_bracket
;----- f_bracket -----------------------------------------------------
; Last char was an escape. This one should be a [; if not, print it.
; Next char should begin a parameter string.
f_bracket:
lodsb
cmp al, '['
jnz fbr_syntax_error_gate
; Set up for getting a parameter string.
mov bx, cs:param_buffer
mov byte ptr cs:[bx], 0
mov cs:in_num, 0
next_is f_get_args
;----- f_get_args ---------------------------------------------------
; Last char was a [. If the current char is a '=' or a '?', eat it.
; In any case, proceed to f_get_param.
; This is only here to strip off the strange chars that follow [ in
; the SET/RESET MODE escape sequence.
f_get_args:
lodsb
cmp al, '='
jz fga_ignore
cmp al, '?'
jz fga_ignore
dec si ; let f_get_param fetch al again
jmp short f_get_param
fga_ignore:
next_is f_get_param
;----- f_get_param ---------------------------------------------------
; Last char was one of the four characters "]?=;".
; We are getting the first digit of a parameter, a quoted string,
; a ;, or a command.
f_get_param:
lodsb
cmp al, '0'
jb fgp_may_quote
cmp al, '9'
ja fgp_may_quote
; It's the first digit. Initialize current parameter with it.
sub al, '0'
mov byte ptr cs:[bx], al
mov cs:in_num, 1 ; set flag for sensing at cmd exec
next_is f_in_param
fgp_may_quote:
cmp al, '"'
jz fgp_isquote
cmp al, "'"
jnz fgp_semi_or_cmd ; jump to code shared with f_in_param
fgp_isquote:
mov cs:string_term, al ; save it for end of string
next_is f_get_string ; and read string into param_buffer
;----- f_get_string -------------------------------------
; Last character was a quote or a string element.
; Get characters until ending quote found.
f_get_string:
lodsb
cmp al, cs:string_term
jz fgs_init_next_param
mov byte ptr cs:[bx], al
cmp bx, cs:param_end
adc bx, 0 ; if bx<param_end bx++;
next_is f_get_string
; Ending quote was found.
fgs_init_next_param:
mov byte ptr cs:[bx], 0 ; initialize new parameter
; | Eat following semicolon, if any.
next_is f_eat_semi
;----- f_eat_semi -------------------------------------
; Last character was an ending quote.
; If this char is a semi, eat it; else unget it.
; Next state is always f_get_param.
f_eat_semi:
lodsb
cmp al, ';'
jz fes_eaten
inc cx
dec si
fes_eaten:
next_is f_get_param
;----- syntax_error ---------------------------------------
; A character was rejected by the state machine. Exit to
; main loop, and print offending character. Let main loop
; decrement CX (length of input string).
syntax_error:
mov cs:escvector, 0
mov ah, cs:cur_attrib
mov bx, cs:xlate_tab_ptr
jmp f_not_ANSI ; exit, print offending char
;------ f_in_param -------------------------------------
; Last character was a digit.
; Looking for more digits, a semicolon, or a command character.
f_in_param:
lodsb
cmp al, '0'
jb fgp_semi_or_cmd
cmp al, '9'
ja fgp_semi_or_cmd
; It's another digit. Add into current parameter.
sub al, '0'
xchg byte ptr cs:[bx], al
push dx
mov dl, 10
mul dl
pop dx
add byte ptr cs:[bx], al
next_is f_in_param
; Code common to states get_param and in_param.
; Accepts a semicolon or a command letter.
fgp_semi_or_cmd:
cmp al, ';'
jnz fgp_not_semi
cmp bx, cs:param_end ; prepare for next param-
adc bx, 0 ; if bp<param_end bp++;
; Set new param to zero, enter state f_get_param.
mov cs:in_num, 0 ; no longer inside number
jmp fgs_init_next_param ; spaghetti code attack!
fgp_not_semi:
; It must be a command letter.
cmp al, '@'
jb syntax_error
cmp al, 'z'
ja syntax_error
cmp al, 'Z'
jbe fgp_is_cmd
cmp al, 'a'
jb syntax_error
; It's a lower-case command letter.
; Remove hole between Z and a to save space in table.
sub al, 'a'-'['
fgp_is_cmd:
; It's a command letter. Save registers, convert letter
; into address of routine, set up new register usage, call routine.
push si ; These three registers hold info
push cx ; having to do with the input string,
push ds ; which has no interest at all to the
; control routine.
push cs
pop ds ; ds is now cs
sub al, '@' ; first command is @: insert chars
cbw
add ax, ax
add ax, offset ansi_fn_table
; ax is now pointer to command routine address in table
mov cx, bx
mov si, param_buffer ; si is now pointer to parameters
sub cx, si ;
test in_num, 1
jz fip_out_num
inc cx
fip_out_num: ; cx is now # of parameters
xchg ax, bx ; save pointer to routine in bx
; Calculate cur_x from DX.
mov al, max_x
inc ax
sub al, dl
mov cur_x, al
; Get first parameter into AX; if defaulted, set it to 1.
mov ah, 0
lodsb
or al, al
jnz fgp_callem
inc ax
cmp ax, ax ; reset the z flag cuz we waz 0 CRH
fgp_callem:
; Finally, call the command subroutine.
call word ptr [bx]
pop ds
pop cx
pop si
mov ah, cs:cur_attrib ; Prepare for STOSW.
mov bx, cs:xlate_tab_ptr ; Prepare for translation.
mov cs:escvector, 0 ; No longer parsing escape sequence.
; Set flags for reentry at loopnz
or dx, dx ; "Any columns left on line?"
; Re-enter at bottom of main loop.
jmp f_ansi_exit
code ends
end ; of nansi_p.asm
page 66, 132